﻿
using Kaliko.ImageLibrary;
using Kaliko.ImageLibrary.Filters;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace Extensions
{
    public static class ImageExtensions
    {
        public static Image Resize(this Image img, int size)
        {
            //a holder for the result
            Bitmap result = new Bitmap(size, size);
            //set the resolutions the same to avoid cropping due to resolution differences
            result.SetResolution(img.HorizontalResolution, img.VerticalResolution);

            //use a graphics object to draw the resized image into the bitmap
            using (Graphics graphics = Graphics.FromImage(result))
            {
                //set the resize quality modes to high quality
                graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
                graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                //draw the image into the target bitmap
                graphics.DrawImage(img, 0, 0, result.Width, result.Height);
            }

            return result as Image;
        }

        public static void SaveAsJPEG(this Image img, string imagePath)
        {
            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
            ImageCodecInfo jgpEncoder = null;

            foreach (ImageCodecInfo codec in codecs)
            {
                if (codec.FormatID == ImageFormat.Jpeg.Guid)
                {
                    jgpEncoder = codec;
                    break;
                }
            }

            Encoder encoder = System.Drawing.Imaging.Encoder.Quality;
            EncoderParameters encoderParameters = new System.Drawing.Imaging.EncoderParameters(1);
            EncoderParameter encoderParameter = new EncoderParameter(encoder, 100L);
            encoderParameters.Param[0] = encoderParameter;

            img.Save(imagePath, jgpEncoder, encoderParameters);
        }

        public static Image Unsharpen(this Image img, double strength = 0.3)
        {
            /*
            KalikoImage sharpimg = new KalikoImage(img).GetThumbnailImage(427, 284, ThumbnailMethod.Fit);
            sharpimg.ApplyFilter(new UnsharpMaskFilter(1.2, 0.3));
            sharpimg.SaveJpg(pathT, 95);
            */
            KalikoImage sharpimg = new KalikoImage(img);
            sharpimg.ApplyFilter(new UnsharpMaskFilter(1.2, 0.5));
            return sharpimg.Image;
        }

        /*
        public static Image Sharpen(this Image img, double strength = 0.3)
        {
            strength = 0.5;
            using (Bitmap bitmap = new Bitmap(img))
            {
                if (bitmap != null)
                {
                    var sharpenImage = bitmap.Clone() as Bitmap;

                    int width = img.Width;
                    int height = img.Height;

                    // Create sharpening filter.
                    const int filterSize = 5;

                    var filter = new double[,]
                {
                    {-1, -1, -1, -1, -1},
                    {-1,  2,  2,  2, -1},
                    {-1,  2, 16,  2, -1},
                    {-1,  2,  2,  2, -1},
                    {-1, -1, -1, -1, -1}
                };

                    double bias = 1.0 - strength;
                    double factor = strength / 16.0;

                    const int s = filterSize / 2;

                    var result = new Color[img.Width, img.Height];

                    // Lock image bits for read/write.
                    if (sharpenImage != null)
                    {
                        BitmapData pbits = sharpenImage.LockBits(new Rectangle(0, 0, width, height),
                                                                    ImageLockMode.ReadWrite,
                                                                    PixelFormat.Format24bppRgb);

                        // Declare an array to hold the bytes of the bitmap.
                        int bytes = pbits.Stride * height;
                        var rgbValues = new byte[bytes];

                        // Copy the RGB values into the array.
                        System.Runtime.InteropServices.Marshal.Copy(pbits.Scan0, rgbValues, 0, bytes);

                        int rgb;
                        // Fill the color array with the new sharpened color values.
                        for (int x = s; x < width - s; x++)
                        {
                            for (int y = s; y < height - s; y++)
                            {
                                double red = 0.0, green = 0.0, blue = 0.0;

                                for (int filterX = 0; filterX < filterSize; filterX++)
                                {
                                    for (int filterY = 0; filterY < filterSize; filterY++)
                                    {
                                        int imageX = (x - s + filterX + width) % width;
                                        int imageY = (y - s + filterY + height) % height;

                                        rgb = imageY * pbits.Stride + 3 * imageX;

                                        red += rgbValues[rgb + 2] * filter[filterX, filterY];
                                        green += rgbValues[rgb + 1] * filter[filterX, filterY];
                                        blue += rgbValues[rgb + 0] * filter[filterX, filterY];
                                    }

                                    rgb = y * pbits.Stride + 3 * x;

                                    int r = Math.Min(Math.Max((int)(factor * red + (bias * rgbValues[rgb + 2])), 0), 255);
                                    int g = Math.Min(Math.Max((int)(factor * green + (bias * rgbValues[rgb + 1])), 0), 255);
                                    int b = Math.Min(Math.Max((int)(factor * blue + (bias * rgbValues[rgb + 0])), 0), 255);

                                    result[x, y] = Color.FromArgb(r, g, b);
                                }
                            }
                        }

                        // Update the image with the sharpened pixels.
                        for (int x = s; x < width - s; x++)
                        {
                            for (int y = s; y < height - s; y++)
                            {
                                rgb = y * pbits.Stride + 3 * x;

                                rgbValues[rgb + 2] = result[x, y].R;
                                rgbValues[rgb + 1] = result[x, y].G;
                                rgbValues[rgb + 0] = result[x, y].B;
                            }
                        }

                        // Copy the RGB values back to the bitmap.
                        System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, pbits.Scan0, bytes);
                        // Release image bits.
                        sharpenImage.UnlockBits(pbits);
                    }

                    return sharpenImage;
                }
            }
            return null;
        }
        */
        public static byte[] ToPNG(this Image img)
        {
            byte[] bytes;
            try
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    img.Save(ms, ImageFormat.Png);
                    bytes = ms.ToArray();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return bytes;
        }

        public static byte[] ToJPEG(this Image img)
        {
            byte[] bytes;
            try
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    img.Save(ms, ImageFormat.Jpeg);
                    bytes = ms.ToArray();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return bytes;
        }

        public static Image CropFromCenter(this Image bmp, int size)
        {
            Rectangle cropRect = new Rectangle((bmp.Width / 2) - (size / 2), (bmp.Height / 2) - (size / 2), size, size);

            Bitmap target = new Bitmap(size, size);

            using (Graphics g = Graphics.FromImage(target))
            {
                g.DrawImage(bmp, new Rectangle(0, 0, target.Width, target.Height),
                                 cropRect,
                                 GraphicsUnit.Pixel);
            }

            return target;
        }

        public static Image Mask(this Image img, Bitmap mask)
        {
            Bitmap target = new Bitmap(img.Width, img.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            Graphics graphics = Graphics.FromImage(target);
            graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;

            graphics.DrawImage(img, 0, 0);
            graphics.DrawImage(mask, 0, 0);

            return target;
        }

        public static Bitmap Crop(this Bitmap bmp, Rectangle rect)
        {
            Bitmap modified = new Bitmap(rect.Width, rect.Height);
            Graphics g = Graphics.FromImage(modified);
            g.DrawImage(bmp, -rect.X, -rect.Y);

            return modified;
        }
    }
}